package com.zc.im.seqsvr.service.impl;

import cn.hutool.core.util.StrUtil;
import com.zc.im.common.r2dbc.domain.AbstractBase;
import com.zc.im.seqsvr.repository.AbstractBaseRepository;
import com.zc.im.seqsvr.service.AbstractBaseService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.r2dbc.core.R2dbcEntityOperations;
import org.springframework.data.relational.core.query.Query;
import org.springframework.data.relational.core.query.Update;
import org.springframework.r2dbc.core.DatabaseClient;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import javax.annotation.PostConstruct;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;

/**
 * Project：download
 * Date：2022/4/13
 * Time：19:00
 * Description：基础service   数据访问仓库命名一定要 实体类名首字母小写 + Repository
 *
 * @author 小帅气
 * @version 1.0
 */
public abstract class AbstractBaseServiceImpl<T extends AbstractBase, D, E extends AbstractBaseRepository> implements AbstractBaseService<T, D, E> {

    private E reactiveCrudRepository;

    @Autowired
    private ApplicationContext applicationContext;

    @Autowired
    private R2dbcEntityOperations r2dbcEntityOperations;

    //@Autowired
    private DatabaseClient databaseClient;

    private Class<T> entityClass;

    public static Class<?> getSuperClassGenericType(final Class<?> clazz, final int index) {
        Type genType = clazz.getGenericSuperclass();
        if (!(genType instanceof ParameterizedType)) {
            return Object.class;
        }
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
        if (index >= params.length || index < 0) {
            return Object.class;
        }
        if (!(params[index] instanceof Class)) {
            return Object.class;
        }
        return (Class<?>) params[index];
    }

    @PostConstruct
    public void initBase() {
        Class<? extends AbstractBaseServiceImpl> aClass = getClass();
        entityClass = (Class<T>) getSuperClassGenericType(aClass, 0);

        String name = StrUtil.lowerFirst(entityClass.getSimpleName());
        Object bean = applicationContext.getBean(name + "Repository");
        databaseClient = r2dbcEntityOperations.getDatabaseClient();
        reactiveCrudRepository = (E) bean;
    }


    @Override
    public Mono<T> findById(D id) {
        return getRepository().findById(id);
    }

    @Override
    public Flux<T> findAll() {
        return getRepository().findAll();
    }

    //@Override
    //public Mono<T> findOneByUserId(Long userId) {
    //    return getRepository().findOneByUserId(userId);
    //}
    //
    //@Override
    //public Flux<T> findAllByUserId(Long userId) {
    //    return getRepository().findAllByUserId(userId);
    //}

    @Override
    public Flux<T> findByIds(Collection<D> ids) {
        return getRepository().findAllById(ids);
    }

    @Override
    public Mono<T> save(T t) {
        return getRepository().save(t);
    }

    @Override
    public Flux<T> saveAll(Iterable<T> iterable) {
        return getRepository().saveAll(iterable);
    }

    @Override
    public Mono<T> delete(T t) {
        return getRepository().deleteById(t);
    }

    @Override
    public E getRepository() {
        return reactiveCrudRepository;
    }

    @Override
    public DatabaseClient getDatabaseClient() {
        return databaseClient;
    }

    @Override
    public R2dbcEntityOperations getOperations() {
        return r2dbcEntityOperations;
    }

    @Override
    public Class<T> getEntityClass() {
        return entityClass;
    }

    @Override
    public Mono<Integer> update(Query query, Update update) {
        return getOperations().update(query, update, entityClass);
    }
}
